package com.util;

import java.awt.geom.Point2D;
import java.util.ArrayList;
import java.util.List;

public class FenceUtils {

    public static boolean checkIsInPolygon(Point checkPoint, List<Point> areaAround) {

        Point2D.Double point = new Point2D.Double(checkPoint.getLat(), checkPoint.getLng());
        List<Point2D.Double> pointList = new ArrayList<>();
        for (Point everyPoint : areaAround) {
            Point2D.Double polygonPoint = new Point2D.Double(everyPoint.getLat(), everyPoint.getLng());
            pointList.add(polygonPoint);
        }
        return checkIsPtInPoly(point, pointList);
    }

    public static boolean checkIsPtInPoly(Point2D.Double point, List<Point2D.Double> pts) {
        int N = pts.size();
        //如果点位于多边形的顶点或边上，也算做点在多边形内，直接返回true
        boolean boundOrVertex = true;
        //cross points count of x
        int intersectCount = 0;
        //浮点类型计算时候与0比较时候的容差
        double precision = 2e-10;
        //neighbour bound vertices
        Point2D.Double p1, p2;
        //当前点
        Point2D.Double p = point;
        //left vertex
        p1 = pts.get(0);
        //check all rays
        for (int i = 1; i <= N; ++i) {
            if (p.equals(p1)) {
                //p is an vertex
                return boundOrVertex;
            }
            //right vertex
            p2 = pts.get(i % N);
            //ray is outside of our interests
            if (p.x < Math.min(p1.x, p2.x) || p.x > Math.max(p1.x, p2.x)) {
                p1 = p2;
                //next ray left point
                continue;
            }
            //ray is crossing over by the algorithm (common part of)
            if (p.x > Math.min(p1.x, p2.x) && p.x < Math.max(p1.x, p2.x)) {
                //x is before of ray
                if (p.y <= Math.max(p1.y, p2.y)) {
                    //overlies on a horizontal ray
                    if (p1.x == p2.x && p.y >= Math.min(p1.y, p2.y)) {
                        return boundOrVertex;
                    }
                    //ray is vertical
                    if (p1.y == p2.y) {
                        //overlies on a vertical ray
                        if (p1.y == p.y) {
                            return boundOrVertex;
                            //before ray
                        } else {
                            ++intersectCount;
                        }
                    } else {
                        //cross point on the left side
                        //cross point of y
                        double xinters = (p.x - p1.x) * (p2.y - p1.y) / (p2.x - p1.x) + p1.y;
                        //overlies on a ray
                        if (Math.abs(p.y - xinters) < precision) {
                            return boundOrVertex;
                        }
                        //before ray
                        if (p.y < xinters) {
                            ++intersectCount;
                        }
                    }
                }
            } else {
                //special case when ray is crossing through the vertex
                //p crossing over p2
                if (p.x == p2.x && p.y <= p2.y) {
                    //next vertex
                    Point2D.Double p3 = pts.get((i + 1) % N);
                    //p.x lies between p1.x & p3.x
                    if (p.x >= Math.min(p1.x, p3.x) && p.x <= Math.max(p1.x, p3.x)) {
                        ++intersectCount;
                    } else {
                        intersectCount += 2;
                    }
                }
            }
            //next ray left point
            p1 = p2;
        }
        //偶数在多边形外
        if (intersectCount % 2 == 0) {
            return false;
        } else {
            //奇数在多边形内
            return true;
        }
    }
}
